#rules module
#!/usr/bin/python
#Filename: rules.py

import logging
import pywapi
import string
import icoach

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.api import mail
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import urlfetch
from datetime import datetime, timedelta

## DATA MODEL ##
class Messages(db.Model):
    email = db.StringProperty()
    date_sent = db.DateTimeProperty(auto_now_add=True)
    msg_id = db.StringProperty()
    
## HELPER METHODS ##
def mailer(user, msg):
    '''Helper method to send messages to users'''    
    subject = "Message from iCoach"
    body = msg
    
    number = user.phone_num
    if number == "None" or number == None or len(number) != 10:
        recipient = user.email
    else:
        append=""
        carrier = user.phone_car
        if carrier == "AT&T":
            append = "@txt.att.net"
        elif carrier == "Alltel":
            append = "@message.alltel.com"
        elif carrier == "T-Mobile":
            append = "@sms.t-mobile.at"
        elif carrier == "Verizon":
            append = "@vtext.com"
        elif carrier == "Virgin Mobile":
            append = "@vmobl.com"
        elif carrier == "Suncom":
            append = "@tms.suncom.com"
        elif carrier == "Sprint (PCS)":
            append = "@messaging.sprintpcs.com"
        elif carrier == "Sprint (Nextel)":
            append = "@page.nextel.com"   
        elif carrier == "Cingular GoPhone":
            append = "@cingularme.com"                                                                      
                            
        number = user.phone_num.replace("-","")
        number = number.replace(" ","")
        recipient = number + append
    
    #sender should be sms@ireminder.net      
    message = mail.EmailMessage(sender = 'magellanscholar@gmail.com',to = recipient, subject = subject, body = body)      
    message.send()
    logging.info('Sent Reminder to %s' % ( recipient))      
    logging.debug('Finish sending message to user')  
    
def getWeather():
    #may want to add user as parameter to check their zipcode
    try:
        google_result = pywapi.get_weather_from_google('29201')
        weather = string.lower(google_result['current_conditions']['condition'])
        return weather
    except:
        return None
    
def getMessages(user):
    '''Returns a list of all messages associated with a user'''
    query = Messages.all()
    query.filter('email =',user.email).order('-date_sent')
    return query.fetch(100,0)

def getTrimester(user):
    '''Returns trimester of a user'''
    query = Profile.all()
    query.filter('email =', user.email)
    due_date = query.get().due_date
    
    if due_date != 'None':
        date_diff = datetime.now() - due_date
        
        logging.debug('Trimester: %s' % date_diff)
        
        if date_diff > timedelta (months = 6):
            trimester = 3
            logging.info('Trimester: %s' % trimester)
        elif date_diff > 3:
            trimester = 2
            logging.info('Trimester: %s' % trimester)
        else:
            trimester = 1
            logging.info('Trimester: %s' % trimester)
        
        logging.debug('Trimester: %s' % trimester)
    return trimester   

def lastSentAMessage(user):
    '''Retrieve time and date last message sent'''                    
    try:
        messages = getMessages(user)                
        previous = messages[0].date_sent    #could also use 'if not messages' to check if list empty        
        elapsed_time = datetime.now() - previous            
        return elapsed_time 
    except:
        return None 
            
def lastSentThisMessage(user, id):
    '''Retrieve time and date specific message last sent'''    
    try:                    
        messages = getMessages(user)       
        for m in messages:         
            if m.msg_id == id:
                previous = m.date_sent
                elapsed_time = datetime.utcnow() - previous           
                return elapsed_time
    except:
        return None

## RULES CLASSES ##  
class Rule():
    id = "XX1"
    weather = 'None'
    
    def getMessage(self, user):
        '''Sends the message to the user'''          
        return "Test"
        
    def sendNow(self, user):
        '''Logically figures out if message should be sent'''  
        return "Test"
                              
class WE1(Rule):
    '''First message sent to all users as a greeting. Sent: Once'''
    id = "WE1"
    def getMessage(self, user):
        return "Welcome to iCoach %s" % user.account
    
    def sendNow(self, user):              
        elapsed_time = lastSentAMessage(user)
        #Restrictions: Sent once. Users should only be sent 1 welcome message        
        if elapsed_time == None:
            return True
        else:                
            messages = getMessages(user)
            for m in messages:         
                if m.msg_id == 'WE1':
                    return False             
            return True       
                            
class SE1(Rule):
    '''Generic walking message. Sent Once a week'''
    id = "SE1"
    def getMessage(self, user):
        return '''Start a Walking program. Start with 5 or 10 min walks and build up
                  slowly to 30 mins/days. You don't have to do 30 minutes at one time.
                  You can take 3 10-min walks or 2 15-min walks.'''
    
    def sendNow(self, user):                
        elapsed_time = lastSentThisMessage(user, SE1.id)
                
        #trimester = getTrimester(user)
        
        #Restrictions: Sent once per week; User must be in 1st trimester
        if elapsed_time == None:
            return True
        else:           
            if elapsed_time > timedelta (days = 7):            
                return True
            else:
                return False
        
class GS1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "GS1"
    def getMessage(self, user):
        return '''Use your pedometer to set goals. If you get 5,000 steps/days
                  now, try to increase by 100 steps/days until you get closer
                  to the goal of ~10,000 steps/days. Write down your steps to see progress.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, GS1.id)
        
        #Restrictions: Sent once per days
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 6):            
                return True
            else:
                return False       

class SR1(Rule):
    '''Generic walking message. Sent Once a week'''
    id = "SR1"
    def getMessage(self, user):
        return '''What do you do to reward yourself when you meet your walking goals?
                  Rewards don't have to cost much money. Make a list of nice things you
                  can do for yourself when you meet goals.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SR1.id)
        
        #Restrictions: Sent once per week. Only if a goal message has been sent
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 5):            
                return True
            else:
                return False
            
class SM1(Rule):
    '''Generic walking message. Sent Once a week'''
    id = "SM1"
    def getMessage(self, user):
        return '''One of the best ways to stay on track is to keep a log. Write down how many days
                  you walked and how many steps you took each days. Use your log to set goals and reward yourself.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SM1.id)
        
        #Restrictions: Sent once per week. Only if a goal message has been sent
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 4):            
                return True
            else:
                return False
            
class PS1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "PS1"
    def getMessage(self, user):
        return '''What is your biggest barrier to walking? Write down this barrier. Try to list at least 3 ways
                  you might try to get around it. Pick the strategy that seems most 'do-able'. Give it a try this week!'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, PS1.id)
        
        #Restrictions: Sent once per days. Only if a goal message has been sent
        if elapsed_time == None:
            return True
        else:
            #if lastSentThisMessage(user, PS.id...
            if elapsed_time > timedelta (days = 3):            
                return True
            else:
                return False
            
class BA1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BA1"
    def getMessage(self, user):
        return '''Too busy to walk? Try to fit in 3 10-min walks in your days instead of 1 30-min walk. Stay active
                  during your favorite tv program. Walk for errands. Park further away from stores.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BA1.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 2):            
                return True
            else:
                return False
            
class BA2(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BA2"
    def getMessage(self, user):
        return '''Too tired to walk? Many women feel tired during their pregnancy. It may not seem like it,
                  but walking can actually boost your energy.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BA2.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 1):            
                return True
            else:
                return False
            
class BA3(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BA3"
    def getMessage(self, user):
        return '''Worried that exercise will harm your body? Brisk walking is recommended for most pregnant women.
                  If you have concerns about the safety of walking for you, talk with your doctor.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BA3.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 7):            
                return True
            else:
                return False
            
class BA4(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BA4"
    def getMessage(self, user):
        return '''Weather's not good? Is there a nearby mall where you could walk? If not, why not try putting
                  on your favorite music and walking or dancing right in your home.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BA4.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
                if elapsed_time > timedelta (days = 6):            
                    return True
                else:
                    return False
            
class BE1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BE1"
    def getMessage(self, user):
        return '''Exercise is good for you and you baby! Did you you take your walk todays?'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BE1.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 5):            
                return True
            else:
                return False
            
class BE2(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BE2"
    def getMessage(self, user):
        return '''Did you know that regular exercise helps reduce symptoms of pregnancy
                  and increases energy? Walking makes you feel good!'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BE2.id)
        
        #Restrictions: Sent once per week.
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 4):            
                return True
            else:
                return False
            
class BE3(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BE3"
    def getMessage(self, user):
        return '''Did you know that exercise can help manage many symptoms in pregnancy? They
                  include backaches, constipation, bloating, swelling, sleep problems and fatigue.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BE3.id)
        
        #Restrictions: Sent once per week.
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 3):            
                return True
            else:
                return False
            
class BE4(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BE4"
    def getMessage(self, user):
        return '''Women who exercise in pregnancy are better able to keep up their energy to deal with the challenges
                  of labor. It is also easier to get back in shape after baby is born if you are active now.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BE4.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 2):            
                return True
            else:
                return False
            
class BE5(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BE5"
    def getMessage(self, user):
        return '''Keeping fit and active during pregnancy helps you to not gain too much weight.
                  Ask your doctor how much weight you should gain during pregnancy.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BE5.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 1):            
                return True
            else:
                return False
            
class BE6(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "BE6"
    def getMessage(self, user):
        return '''How much is enough? Try to walk briskly for at least 30 days each days on five dayss of the week.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, BE6.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 7):            
                return True
            else:
                return False
            
class SC1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SC1"
    def getMessage(self, user):
        return '''Remind yourself! Keep tennis shoes by the door or in your car or office, schedule walking
                  in your calendar, use post-it notes to remind you to walk, or ask a friend to remind you.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SC1.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 6):            
                return True
            else:
                return False
            
class SS1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SS1"
    def getMessage(self, user):
        return '''Need a little help? You might ask your partner or a friend to walk with you.
                  help with other things (e.g., childcare) so you have the time to walk or simply
                  encourage our support you to walk.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SS1.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 5):            
                return True
            else:
                return False
            
class SS2(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SS2"
    def getMessage(self, user):
        return '''Is your family telling you not to exercise? Share with them your doctor's recommendations
                  or give them an article about exercising during pregnancy.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SS2.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 4):            
                return True
            else:
                return False
            
class SA1(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SA1"
    def getMessage(self, user):
        return '''Many exercise are safe during pregnancy. But after your first trimester, 
                  avoid exercises where you lie on your back. Lying on your back can reduce blood flow to the uterus.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SA1.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 3):            
                return True
            else:
                return False
            
class SA2(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SA2"
    def getMessage(self, user):
        return '''Many exercises are safe during pregnancy. But you want to avoid activities where you might
                  fall or be hit in the abdomen (contact sports). Walking and swimming are great and safe choices.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SA2.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 2):            
                return True
            else:
                return False
            
class SA3(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SA3"
    def getMessage(self, user):
        return '''Keep cool! Drink plenty of fluids before and exercise, wear breathable clothing,
                  avoid exercising during the hottest time of the days, and don't use hot tubs or sauna.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SA3.id)
        
        #Restrictions: Sent once per week.
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 1):            
                return True
            else:
                return False
            
class SA4(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SA4"
    def getMessage(self, user):
        return '''Stay comfortable! Wear cool clothing in layers so you can remove layers
           if you get too warm. be sure to wear a bra that fits properly and supports your breasts.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SA4.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 7):            
                return True
            else:
                return False
            
class SA5(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SA5"
    def getMessage(self, user):
        return '''Stay balanced! Pregnancy changes your center of gravity and balance
                  and you are are greater risk for falls. Walk on level, even surfaces and avoid quick turns and moves.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SA5.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 6):            
                return True
            else:
                return False
            
class SA6(Rule):
    '''Generic walking message. Sent Once a days'''
    id = "SA6"
    def getMessage(self, user):
        return '''Stop exercising and see your doctor if you experience: start of pain
                  anywhere in your body, vaginal bleeding or heavy discharge, dizziness, pronounced shortness of breath.'''
    
    def sendNow(self, user):                   
        elapsed_time = lastSentThisMessage(user, SA6.id)
        
        #Restrictions: Sent once per week. Check weather
        if elapsed_time == None:
            return True
        else:
            if elapsed_time > timedelta (days = 5):            
                return True
            else:
                return False                                                                                                                                                                                                                                                                            

## REQUEST HANDLER ##                               
class Reminder(webapp.RequestHandler):
    '''Sends reminders to users'''            
    def get(self):
        logging.debug('Beginning Reminder Service')
        
        rules = []
        rules.append(WE1())     #append all rules       
        rules.append(SE1())
        rules.append(GS1())
        rules.append(SR1())
        rules.append(SM1())
        rules.append(PS1())
        rules.append(BA1())
        rules.append(BA2())
        rules.append(BA3())
        rules.append(BA4())
        rules.append(BE1())
        rules.append(BE2())
        rules.append(BE3())
        rules.append(BE4())
        rules.append(BE5())
        rules.append(BE6())
        rules.append(SC1())
        rules.append(SS1())
        rules.append(SS2())
        rules.append(SA1())
        rules.append(SA2())
        rules.append(SA3())
        rules.append(SA4())
        rules.append(SA5())
        rules.append(SA6())
                
        query = icoach.Profile.all()
        Rule.weather = getWeather()
               
        for r in rules:
            logging.info('Reminder ID: %s' % r.id)
            for user in query:
                logging.info('User: %s' % user.account)
                if r.sendNow(user) == True:                   
                    mailer(user, r.getMessage(user))                    
                    id = r.id                    
                    sentMessage = Messages(email=user.email,msg_id=id)
                    sentMessage.put()
                    logging.info('Added message to database')
                else:
                    logging.info('Message not sent')    
        logging.debug('Finished Reminder Service')    
                
application = webapp.WSGIApplication(
                                     [('/sms/rules', Reminder)],
                                     debug=True)
  
def main():
    logging.getLogger().setLevel(logging.DEBUG)
    run_wsgi_app(application)

if __name__ == "__main__":
    main()